﻿#ifndef FFMPEGTHREAD_H
#define FFMPEGTHREAD_H
#include <thread>
#include <string>
extern "C" {
#include <libavcodec/codec_id.h>
#include <libavutil/pixfmt.h>
#include <libavutil/avutil.h>
}
#ifdef _WIN32
typedef std::string SharedId;
#else
typedef size_t SharedId;

#endif
struct AVFilterContext;
struct AVFilterGraph;
struct AVDictionary;
struct AVFormatContext;
struct AVCodec;
struct AVCodecContext;
struct AVStream;
struct AVFrame;
struct AVPacket;

class CProcessMutex;
class IPC_MSG;

typedef struct OutputStreamContext {
    AVCodecID codec_id;//编码器id
    AVMediaType media_type;//媒体类型
    //输出视频参数
    short aspect_w;//AVRational aspect_ratio;//宽高比
    short aspect_h;
    unsigned int framerate_num;//AVRational framerate;//25/1 25帧/1秒钟
    unsigned int framerate_den;
    AVPixelFormat pix_fmt;//像素格式
    int width;//图像宽度
    int height;//图像高度
    //输出音频参数
    uint64_t channel_layout;//音频通道布局 单声道:av_get_channel_layout("mono") 双声道: av_get_channel_layout("stereo")
    int sample_fmt;//音频样本格式  U8 S16 FLT
    int sample_rate;//音频频率 44100
}OutputStreamContext;

typedef struct FilteringContext {
    AVFilterContext* buffersink_ctx=nullptr;
    AVFilterContext* buffersrc_ctx=nullptr;
    AVFilterGraph* filter_graph=nullptr;
} FilteringContext;
enum { Y, U, V, A };


class FFmpegThread
{
public:
    FFmpegThread();
    ~FFmpegThread();
    void set_enable_ipc(SharedId mmid,const std::string& mxid);
    bool allocate_ipc_resource();
    bool open_input_stream(const char* url);
    void close_input_stream();
    bool init_decode_context(const unsigned int stream_index);
    bool init_filter_context(const unsigned int stream_index);
    bool init_encode_context(AVMediaType stream_index);
    bool open_output_stream(const char* url,const char* fmt = NULL);
    void close_output_stream();
    void update_filter_description(AVMediaType media_type, const std::string& desc);

    int encode_write_frame(const unsigned int stream_index,AVFrame* write_frame);
    void run();
    void start();
    void terminate();
private:

    void attach_bboxes_side_data_for_frame(int objcount, unsigned int boxes[][5]);


public:
    int input_streams_count = 0;
    int input_vid = -1;
    int input_aid = -1;

    int output_vid=-1;
    int output_aid=-1;

private:
    bool ipc_enable=false;
    SharedId mem_id;
    IPC_MSG* ipc_message=nullptr;
    std::string mutx_id;
    CProcessMutex* ipc_mutex=nullptr;

private:
    AVDictionary* input_config=nullptr;
    AVFormatContext* ic=nullptr;
    const AVCodec* vdecodec=nullptr;
    const AVCodec* adecodec=nullptr;
    AVCodecContext* vdecoder_ctx = nullptr;
    AVCodecContext* adecoder_ctx = nullptr;
    AVStream* vstream=nullptr;
    AVStream* astream=nullptr;
    AVPacket* raw_packet=nullptr;
    AVFrame* decode_frame=nullptr;

private:
    bool v_filter_update_enable=true;
    bool a_filter_update_enable=true;
    std::string vdesc="null";
    std::string adesc="anull";
    AVFrame* filtered_frame;
    FilteringContext* vfilter_ctx=nullptr;
    FilteringContext* afilter_ctx=nullptr;
private:
    AVDictionary* output_config=nullptr;
    AVFormatContext* oc=nullptr;
    const AVCodec* vencodec = nullptr;
    const AVCodec* aencodec = nullptr;
    AVCodecContext* vencoder_ctx = nullptr;
    AVCodecContext* aencoder_ctx = nullptr;
    AVPacket* encoded_packet=nullptr;
    OutputStreamContext vstream_ctx;
    OutputStreamContext astream_ctx;
    AVStream* video_out_stream=nullptr;
    AVStream* audio_out_stream=nullptr;
    int64_t last_frame_pkt_dts=-1;

private:
    bool termin=false;
    std::thread worker;
};

#endif // FFMPEGTHREAD_H
